前一篇文章中介绍了WKWebView的一下常用属性以及常用API,那么在这篇文章中将主要讲述WKWebView在使用过程中遇到的一些坑。

1.白屏问题

在UIWebView上个当内存占用太大时,app会直接crash,而在WKWebView上内存占用太大时,WebContent Process 会 crash,从而导致页面白屏。

解决办法:

在iOS9之后WKNavigtionDelegate 新增了一个回调函数:

1
- (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView;

在WebContent Process即将crash的时候,系统会调用上面的函数,这个时候webView.URL还不为空,所以我们直接在上面的这个回调里面调用[webView reload],问题得到解决。

2.双击页面导致客户端崩溃问题

报错信息:

1
[WKContentView isSecureTextEntry]: unrecognized selector sent to instance 0x101bd5000

从这个报错信息表明WKContentView没有找到isSecureTextEntry方法,在查找各种资料无果后决定用runtime的方式给WKContentView加上该方法,简单粗暴。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
+ (void)progressWKContentViewCrash 
{
if (([[[UIDevice currentDevice] systemVersion] doubleValue] >= 8.0))
{
const char *className = @"WKContentView".UTF8String;

Class WKContentViewClass = objc_getClass(className);

SEL isSecureTextEntry = NSSelectorFromString(@"isSecureTextEntry");

SEL secureTextEntry = NSSelectorFromString(@"secureTextEntry");

BOOL addIsSecureTextEntry = class_addMethod(WKContentViewClass, isSecureTextEntry, (IMP)isSecureTextEntryIMP, "B@:");

BOOL addSecureTextEntry = class_addMethod(WKContentViewClass, secureTextEntry, (IMP)secureTextEntryIMP, "B@:");

if (!addIsSecureTextEntry || !addSecureTextEntry)
{
NSLog(@"WKContentView-Crash->修复失败");
}
}
}

/**
实现WKContentView对象isSecureTextEntry方法
@return NO
*/
BOOL isSecureTextEntryIMP(id sender, SEL cmd) {
return NO;
}

/**
实现WKContentView对象secureTextEntry方法
@return NO
*/
BOOL secureTextEntryIMP(id sender, SEL cmd) {
return NO;
}

以上progressWKContentViewCrash方法只需要调用一次即可,无需多次调用。

3.页面无法释放问题

在实际使用过程当中,发现使用了WKWebView的界面始终无法释放,在排除了其他因素之后,把目光转向了WKWebView。经过排查之后发现,在初始化webview的时候是这样的:

1
webview = [[WKWebView alloc]initWithFrame:frame configuration:configuration];

然而webview为了与js进行交互,configuration的userContentController属性添加了一个WKScriptMessageHandler:

1
[configuration.userContentController addScriptMessageHandler:self name:@"methodName"];

因为webview的持有者是controller,然后controller又被configuration.userContentController强引用,所以导致页面无法释放。所以这里建议将handler设置成一个管理类,并且在页面的delloc中将其移除。

1
2
3
4
5
6
[configuration.userContentController addScriptMessageHandler:handlerManager name:@"methodName"];

- (void)dealloc
{
[webview.configuration.userContentController removeScriptMessageHandlerForName:@"AppNestCall"];
}

4.Alert相关问题

4.1、Js执行alert方法不弹出alert问题

首先确定webview的回调中已经实现了alert,然后在判断alert弹出时是否有其他界面正在弹出或消失,若有,则在动画结束之后再弹出alert。

1
-(void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler;

4.2、Alert崩溃问题

确保最后的completionHandler被执行。

5、其它问题

5.1、视频自动播放

WKWebView 需要通过WKWebViewConfiguration.mediaPlaybackRequiresUserAction设置是否允许自动播放,但一定要在 WKWebView 初始化之前设置,在 WKWebView 初始化之后设置无效。

5.2、goBack API问题

WKWebView 上调用 -[WKWebView goBack], 回退到上一个页面后不会触发window.onload()函数、不会执行JS。

5.3、页面滚动速率

WKWebView 需要通过scrollView delegate调整滚动速率:

1
2
3
4
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView 
{
scrollView.decelerationRate = UIScrollViewDecelerationRateNormal;
}